#!/usr/bin/python
# -*- coding: utf-8 -*-


from utils import parse_datetime, parse_html_value, parse_a_href, \
        parse_search_datetime, unescape_html
from error import APIError


class Response(object):
    """class for representing success response"""


class Model(object):

    def __init__(self, api=None):
        self._api = api

    def __getstate__(self):
        # pickle
        pickle = dict(self.__dict__)
        del pickle['_api']  # do not pickle the API reference
        return pickle

    @classmethod
    def parse(cls, api, json):
        """Parse a JSON object into a model instance."""
        raise NotImplementedError

    @classmethod
    def parse_list(cls, api, json_list):
        """
        Parse a list of JSON objects into a result \
        set of model instances.
        """
        results = []
        for obj in json_list:
            results.append(cls.parse(api, obj))
        return results

    @classmethod
    def parse_string(cls, api, data):
        """
        Parse a string result
        """
        raise NotImplementedError

    @classmethod
    def parse_direct(cls, api, json):
        """parse json directly"""
        model = cls(api)
        if json is not None:
            for k, v in json.items():
                setattr(model, k, v)
        return model


class Basic(Model):
    """
    class for parsing basic data
    """
    @classmethod
    def parse(cls, api, json):
        """parse basic data"""
        basic = cls(api)
        if json is not None:
            for k, v in json.items():
                setattr(basic, k, v)
        return basic


class Fan(Model):
    """
    class for parsing fan information
    """
    @classmethod
    def parse(cls, api, json):
        """parse fan information"""
        model = cls(api)
        response = Response()
        if json is not None:
            for k, v in json.items():
                if k == 'data':
                    if v is not None:
                        for dk, dv in v.items():
                            if dk == 'info':
                                setattr(model, dk, \
                                        Fan.parse_list_direct(api, dv))
                            else:
                                setattr(model, dk, dv)
                        setattr(response, k, model)
                    else:
                        setattr(response, k, v)
                else:
                    setattr(response, k, v)
            return response
        else:
            raise APIError("Error Response!")

    @classmethod
    def parse_list_direct(cls, api, json_list):
        """parse a fan list"""
        if json_list is not None:
            fanlist = []
            for json in json_list:
                fanlist.append(Fan.parse_direct(api, json))
            return fanlist
        else:
            return json_list

    @classmethod
    def parse_direct(cls, api, json):
        """parse a fan directly"""
        fan = cls(api)
        if json is not None:
            for k, v in json.items():
                if k == 'tweet':
                    if v is not None:
                        setattr(fan, k, Weibo.parse_list_direct(api, v))
                    else:
                        setattr(fan, k, v)
                elif k == 'tag':
                    if v is not None:
                        setattr(fan, k, Tag.parse_list_direct(api, v))
                    else:
                        setattr(fan, k, v)
                else:
                    setattr(fan, k, v)
            return fan
        else:
            raise APIError("Error Response!")


class Id(Model):
    """
    class for parsing id results
    """
    @classmethod
    def parse(cls, api, json):
        """Parse id result"""
        id = cls(api)
        response = Response()
        if json is not None:
            for k, v in json.items():
                if k == 'data':
                    if v is not None:
                        for dk, dv in v.items():
                            setattr(id, dk, dv)
                        setattr(response, k, id)
                    else:
                        setattr(response, k, v)
                else:
                    setattr(response, k, v)
            return response
        else:
            raise APIError("Wrong Response!")


class Relation(Model):
    """
    class for parsing relation information
    """
    @classmethod
    def parse(cls, api, json):
        """parse relation information"""
        relation = cls(api)
        response = Response()
        if json is not None:
            for k, v in json.items():
                if k == 'data':
                    if v is not None:
                        for dk, dv in v.items():
                            if isinstance(dv, dict):
                                setattr(relation, dk, \
                                        Model.parse_direct(api, dv))
                            else:
                                setattr(relation, dk, dv)
                        setattr(response, k, relation)
                    else:
                        setattr(response, k, v)
                else:
                    setattr(response, k, v)
            return response
        else:
            raise APIError("Wrong Response!")



class Tag(Model):
    """
    class for parsing tag information
    """
    @classmethod
    def parse_direct(cls, api, json):
        """parse one tag"""
        tag = Tag(api)
        if json is not None:
            for k, v in json.items():
                setattr(tag, k, v)
            return tag
        else:
            raise APIError("Error Response1")
    
    @classmethod
    def parse_list_direct(cls, api, json_list):
        """parsing a list of tag"""
        tagList = []
        if json_list is not None:
            if len(json_list) > 0:
                for json in json_list:
                    tagList.append(cls.parse_direct(api, json))
                return tagList
            else:
                raise APIError("Error Response!")
        else:
            raise APIError("Error Response!")



class TCount(Model):
    """
    class for parsing t count information
    """
    @classmethod
    def parse(cls, api, json):
        """parse t count information"""
        tcount = cls(api)
        response = Response()
        if json is not None:
            for k, v in json.items():
                if k == 'data':
                    if v is not None:
                        for dk, dv in v.items():
                            if isinstance(dv, dict):
                                setattr(tcount, dk, \
                                        Model.parse_direct(api, dv))
                            else:
                                setattr(tcount, dk, dv)
                        setattr(response, k, tcount)
                    else:
                        setattr(response, k, v)
                else:
                    setattr(response, k, v)
            return response
        else:
            raise APIError("Wrong Response!")


class TimeLine(Model):
    """
    class for parsing weibo information
    """
    @classmethod
    def parse(cls, api, json):
        """Parse weibo information"""
        timeline = cls(api)
        response = Response()
        if json is not None:
            for k, v in json.items():
                if k == 'data':
                    if v is not None:
                        for dk, dv in v.items():
                            if dk == 'info':
                                setattr(timeline, dk, \
                                        Weibo.parse_list_direct(api, dv))
                            else:
                                setattr(timeline, dk, dv)
                            if dk == 'user':
                                setattr(timeline, dk, \
                                        User.parse_list_direct(api, dv))
                        setattr(response, k, timeline)
                    else:
                        setattr(response, k, v)
                else:
                    setattr(response, k, v)
            return response
        else:
            raise APIError("Wrong Response!")


class Token(Model):
    """
    class for parsing token results
    """
    @classmethod
    def parse_string(cls, api, data):
        """Parse the string result"""
        token = cls(api)
        datalist = data.split('&')
        if len(datalist) < 2:
            raise APIError("Wrong response!")
        for tdata in datalist:
            pair = tdata.split('=', 1)
            setattr(token, pair[0], pair[1])
        response = Response()
        setattr(response, 'ret', 0)
        setattr(response, 'msg', 'ok')
        setattr(response, 'data', token)
        return response


class User(Model):
    """
    class for parsing user information
    """
    @classmethod
    def parse(cls, api, json):
        """parse user information"""
        user = cls(api)
        response = Response()
        if json is not None:
            for k, v in json.items():
                if k == 'data':
                    if v is not None:
                        for dk, dv in v.items():
                            if dk == 'tag':
                                if dv is not None:
                                        setattr(user, dk, \
                                        Tag.parse_list_direct(api, dv))
                                else:
                                    setattr(user, dk, dv)
                            else:
                                setattr(user, dk, dv)
                        setattr(response, k, user)
                    else:
                        setattr(response, k, v)
                else:
                    setattr(response, k, v)
            return response
        else:
            raise APIError("Wrong Response!")

    @classmethod
    def parse_list(cls, api, json_list):
        """parse list of user information"""
        userlist = []
        for obj in json_list:
            userlist.append(cls.parse(api, obj))
        return userlist
    
    @classmethod
    def parse_list_direct(cls, api, json):
        """parse json file contains a list of user"""
        userlist = []
        for k, v in json.items():
            user = cls(api)
            setattr(user, 'username', k)
            setattr(user, 'nickname', v)
            userlist.append(user)
        return userlist


class Video(Model):
    """
    class for parsing video information
    """
    @classmethod
    def parse(cls, api, json):
        """parse video information"""
        video = cls(api)
        response = Response()
        if json is not None:
            for k, v in json.items():
                if k == 'data':
                    if v is not None:
                        for dk, dv in v.items():
                            setattr(video, dk, dv)
                        setattr(response, k, video)
                    else:
                        setattr(response, k, v)
                else:
                    setattr(response, k, v)
            return response
        else:
            raise APIError("Wrong Response!")


class Weibo(Model):
    """
    class for parsing a list of Weibo
    """
    @classmethod
    def parse(cls, api, json):
        """Pares weibo response"""
        response = Response()
        if json is not None:
            for k, v in json.items():
                if k == 'data':
                    if v != None:
                        setattr(response, k, Weibo.parse_direct(api, v))
                    else:
                        setattr(response, k, v)
                else:
                    setattr(response, k, v)
            return response
        else:
            raise APIError("Wrong Response!")


    @classmethod
    def parse_direct(cls, api, json):
        """Parse one weibo information"""
        weibo = cls(api)
        for k, v in json.items():
            if k == 'source':
                if v is not None:
                    setattr(weibo, k, Weibo.parse_direct(api, v))
                else:
                    setattr(weibo, k, v)
            else:
                setattr(weibo, k, v)
        return weibo

    @classmethod
    def parse_list_direct(cls, api, json_list):
        """Parse list of weibo"""
        weibolist = []
        for obj in json_list:
            weibolist.append(cls.parse_direct(api, obj))
        return weibolist


class ModelFactory(object):
    """
    Used by parsers for creating instances
    of models. You may subclass this factory
    to add your own extended models.
    """
    basic = Basic
    fan = Fan
    id = Id
    relation=Relation
    tcount = TCount
    timeline = TimeLine
    token = Token
    user = User
    video = Video
    weibo = Weibo
